package com.miracle.schedule.dynamicSchedule;

import com.miracle.schedule.spring.SpringUtils;
import com.miracle.schedule.web.controller.ScheduleController;
import com.miracle.schedule.web.model.ScheduleModel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.SchedulingException;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.config.ScheduledTask;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import org.springframework.scheduling.config.TriggerTask;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;


/**
 *
 * @Description 动态定时任务配置类
 * @Author  miracle
 * @Date   2021/11/1 14:56
 */
@EnableScheduling
@Component
// @Slf4j
public class DynamicScheduleConfigurer implements SchedulingConfigurer {
    private static final Logger log = LoggerFactory.getLogger(DynamicScheduleConfigurer.class);

    private final String FIELD_SCHEDULED_FUTURES = "scheduledTasks";//scheduledFutures  scheduledTasks
    private ScheduledTaskRegistrar scheduledTaskRegistrar;
    private Set<ScheduledTask> scheduledTasks = null;
    private Map<String, ScheduledTask> scheduledTaskMap = new ConcurrentHashMap<>();//维护任务容器

    /**
     * @Description 定时任务配置初始化
     * @Author  miracle
     * @Date   2021/11/3 10:28
     * @Param
     * @Return
     * @Exception
     *
     */
    @Override
    public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
        this.scheduledTaskRegistrar = scheduledTaskRegistrar;
        //修改线程池
        ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler();
        threadPoolTaskScheduler.setPoolSize(10);
        threadPoolTaskScheduler.setThreadNamePrefix("task-");
        threadPoolTaskScheduler.setAwaitTerminationSeconds(60);
        threadPoolTaskScheduler.setWaitForTasksToCompleteOnShutdown(true);
        threadPoolTaskScheduler.setRemoveOnCancelPolicy(true);
        threadPoolTaskScheduler.initialize();
        scheduledTaskRegistrar.setTaskScheduler(threadPoolTaskScheduler);

        //TODO 从数据库查询任务配置
        List<ScheduleModel> list = new ArrayList<>();
        list.add(new ScheduleModel("task1","任务一","testTriggerTask1","cron","0/20 * * * * ?",0));
        list.add(new ScheduleModel("task2","任务二","testTriggerTask2","cron","0/30 * * * * ?",0));
        list.add(new ScheduleModel("task3","任务三","testTriggerTask3","cron","0 0/1 * * * ?",0));
        list.add(new ScheduleModel("task4","任务四","testTriggerTask4","cron","0 0/2 * * * ?",0));

        //加载定时任务
        for (ScheduleModel model : list) {
            String scheduleBean = model.getScheduleBean();
            String scheduleId = model.getScheduleId();

            Runnable bean =  SpringUtils.getBean(scheduleBean);
            addTriggerTask(scheduleId,new TriggerTask(
                    bean,new CronTrigger(model.getScheduleExpr())
            ));
            log.debug(scheduleId + "任务加载成功");
        }
    }


    private Set<ScheduledTask> getScheduledFutures()
    {
        if (scheduledTasks == null)
        {
            try {
                scheduledTasks = (Set<ScheduledTask>) BeanUtils.getProperty(scheduledTaskRegistrar, FIELD_SCHEDULED_FUTURES);
            } catch (NoSuchFieldException e) {
                log.error(e.getMessage(),e);
            }
        }
        return scheduledTasks;
    }

    /**
     * 添加任务
     *
     * @param taskId
     * @param triggerTask
     */
    public void addTriggerTask(String taskId, TriggerTask triggerTask)
    {
        if (hasTask(taskId)) throw new SchedulingException("the taskId[" + taskId + "] has added.");
        if (null == triggerTask) throw new SchedulingException("the triggerTask[" + taskId + "] was null.");

        ScheduledTask scheduledTask = scheduledTaskRegistrar.scheduleTriggerTask(triggerTask);

        getScheduledFutures().add(scheduledTask);
        scheduledTaskMap.put(taskId, scheduledTask);
    }

    /**
     * 取消任务
     *
     * @param taskId
     */
    public ScheduledTask cancelTriggerTask(String taskId)
    {
        ScheduledTask future = scheduledTaskMap.get(taskId);
        if (future != null)
        {
            future.cancel();
            scheduledTaskMap.remove(taskId);
            getScheduledFutures().remove(future);
        }
        return future;
    }

    /**
     * 重置任务
     *
     * @param taskId
     * @param triggerTask
     */
    public void resetTriggerTask(String taskId, TriggerTask triggerTask)
    {
        ScheduledTask scheduledTask = cancelTriggerTask(taskId);
        if (null == scheduledTask) log.warn("reset a empty task!");
        addTriggerTask(taskId, triggerTask);
    }

    /**
     * 任务编号
     *
     * @return
     */
    public Set<String> taskIds()
    {
        return scheduledTaskMap.keySet();
    }

    /**
     * 是否存在任务
     *
     * @param taskId
     * @return
     */
    public boolean hasTask(String taskId)
    {
        return this.scheduledTaskMap.containsKey(taskId);
    }

    /**
     * 任务调度是否已经初始化完成
     *
     * @return
     */
    public boolean inited()
    {
        return this.scheduledTaskRegistrar != null && this.scheduledTaskRegistrar.getScheduler() != null;
    }
}
